package com.smart.community.user.service.impl;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.user.entity.Captcha;
import com.smart.community.user.mapper.CaptchaMapper;
import com.smart.community.user.service.CaptchaService;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;

/**
 * 验证码服务实现类
 * 
 * @author Wu.Liang
 * @since 2024-12-21
 */
@Slf4j
@Service
public class CaptchaServiceImpl extends ServiceImpl<CaptchaMapper, Captcha> implements CaptchaService {

    @Autowired
    private CaptchaMapper captchaMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    // Redis key前缀
    private static final String CAPTCHA_KEY_PREFIX = "captcha:";
    private static final String SMS_CAPTCHA_PREFIX = "sms_captcha:";
    private static final String EMAIL_CAPTCHA_PREFIX = "email_captcha:";

    // 验证码配置
    private static final int CAPTCHA_LENGTH = 4;
    private static final int SMS_CAPTCHA_LENGTH = 6;
    private static final int CAPTCHA_EXPIRE_MINUTES = 5;
    private static final int SMS_CAPTCHA_EXPIRE_MINUTES = 10;

    @Override
    @GlobalTransactional
    public CaptchaInfo generateImageCaptcha() throws Exception {
        // 生成4位随机数字验证码
        String captchaText = generateRandomNumberCode(CAPTCHA_LENGTH);

        // 生成验证码key
        String captchaKey = generateCaptchaKey();

        // 生成验证码图片
        String imageBase64 = generateCaptchaImage(captchaText);

        // 存储验证码到Redis
        String redisKey = CAPTCHA_KEY_PREFIX + captchaKey;
        redisTemplate.opsForValue().set(redisKey, captchaText, CAPTCHA_EXPIRE_MINUTES, TimeUnit.MINUTES);

        // 同时保存到数据库
        saveCaptchaToDatabase(captchaKey, captchaText, 1, null);

        log.info("图形验证码生成成功 - Key: {}, 验证码: {}", captchaKey, captchaText);
        return new CaptchaInfo(captchaKey, imageBase64, captchaText);
    }

    @Override
    public boolean verifyImageCaptcha(String captchaKey, String captcha) throws Exception {
        if (StrUtil.isBlank(captchaKey) || StrUtil.isBlank(captcha)) {
            return false;
        }

        // 从Redis验证
        String redisKey = CAPTCHA_KEY_PREFIX + captchaKey;
        String storedCaptcha = redisTemplate.opsForValue().get(redisKey);
        
        if (StrUtil.isBlank(storedCaptcha)) {
            return false;
        }

        // 验证成功后删除验证码
        redisTemplate.delete(redisKey);

        // 标记数据库中的验证码为已使用
        captchaMapper.markAsUsed(captchaKey);

        return captcha.equalsIgnoreCase(storedCaptcha);
    }

    @Override
    public void sendSmsCaptcha(String phone) throws Exception {
        if (StrUtil.isBlank(phone)) {
            throw new IllegalArgumentException("手机号不能为空");
        }

        // 检查发送频率
        if (isSmsCaptchaLimitExceeded(phone)) {
            log.warn("短信验证码发送频率超限 - 手机号: {}", phone);
            throw new RuntimeException("短信验证码发送频率超限");
        }

        // 生成6位数字验证码
        String captchaCode = generateRandomNumberCode(SMS_CAPTCHA_LENGTH);
        String captchaKey = generateCaptchaKey();

        // 存储到Redis
        String redisKey = SMS_CAPTCHA_PREFIX + captchaKey;
        redisTemplate.opsForValue().set(redisKey, captchaCode, SMS_CAPTCHA_EXPIRE_MINUTES, TimeUnit.MINUTES);

        // 保存到数据库
        saveCaptchaToDatabase(captchaKey, captchaCode, 2, phone);

        // TODO: 调用短信服务发送验证码
        log.info("短信验证码发送成功 - 手机号: {}, 验证码: {}", phone, captchaCode);
    }

    @Override
    public boolean verifySmsCaptcha(String phone, String captcha) throws Exception {
        if (StrUtil.isBlank(phone) || StrUtil.isBlank(captcha)) {
            return false;
        }

        // 从数据库查询验证码
        LambdaQueryWrapper<Captcha> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Captcha::getTarget, phone)
               .eq(Captcha::getCaptchaType, 2)
               .eq(Captcha::getUsed, 0)
               .gt(Captcha::getExpireTime, LocalDateTime.now())
               .orderByDesc(Captcha::getCreateTime)
               .last("LIMIT 1");

        Captcha captchaEntity = captchaMapper.selectOne(wrapper);
        if (captchaEntity == null) {
            return false;
        }

        // 验证验证码
        if (!captcha.equals(captchaEntity.getCaptchaValue())) {
            return false;
        }

        // 标记为已使用
        captchaMapper.markAsUsed(captchaEntity.getCaptchaId());

        return true;
    }

    @Override
    public void sendEmailCaptcha(String email) throws Exception {
        if (StrUtil.isBlank(email)) {
            throw new IllegalArgumentException("邮箱不能为空");
        }

        // 检查发送频率
        if (isEmailCaptchaLimitExceeded(email)) {
            log.warn("邮箱验证码发送频率超限 - 邮箱: {}", email);
            throw new RuntimeException("邮箱验证码发送频率超限");
        }

        // 生成6位数字验证码
        String captchaCode = generateRandomNumberCode(SMS_CAPTCHA_LENGTH);
        String captchaKey = generateCaptchaKey();

        // 存储到Redis
        String redisKey = EMAIL_CAPTCHA_PREFIX + captchaKey;
        redisTemplate.opsForValue().set(redisKey, captchaCode, SMS_CAPTCHA_EXPIRE_MINUTES, TimeUnit.MINUTES);

        // 保存到数据库
        saveCaptchaToDatabase(captchaKey, captchaCode, 3, email);

        // TODO: 调用邮件服务发送验证码
        log.info("邮箱验证码发送成功 - 邮箱: {}, 验证码: {}", email, captchaCode);
    }

    @Override
    public boolean verifyEmailCaptcha(String email, String captcha) throws Exception {
        if (StrUtil.isBlank(email) || StrUtil.isBlank(captcha)) {
            return false;
        }

        // 从数据库查询验证码
        LambdaQueryWrapper<Captcha> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Captcha::getTarget, email)
               .eq(Captcha::getCaptchaType, 3)
               .eq(Captcha::getUsed, 0)
               .gt(Captcha::getExpireTime, LocalDateTime.now())
               .orderByDesc(Captcha::getCreateTime)
               .last("LIMIT 1");

        Captcha captchaEntity = captchaMapper.selectOne(wrapper);
        if (captchaEntity == null) {
            return false;
        }

        // 验证验证码
        if (!captcha.equals(captchaEntity.getCaptchaValue())) {
            return false;
        }

        // 标记为已使用
        captchaMapper.markAsUsed(captchaEntity.getCaptchaId());

        return true;
    }

    /**
     * 生成随机数字验证码
     */
    private String generateRandomNumberCode(int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append((int) (Math.random() * 10));
        }
        return sb.toString();
    }

    /**
     * 生成验证码key
     */
    private String generateCaptchaKey() {
        return "captcha_" + IdUtil.fastSimpleUUID();
    }

    /**
     * 生成验证码图片（实际实现）
     * 
     * @param code 验证码文本
     * @return Base64编码的图片
     */
    private String generateCaptchaImage(String code) {
        // 实际项目中应该使用图形验证码库（如Kaptcha、EasyCaptcha等）
        // 这里模拟生成成功，返回base64图片数据
        try {
            log.info("生成图片验证码成功，验证码：{}", code);
            return "";
        } catch (Exception e) {
            log.error("生成图片验证码失败，验证码：{}", code, e);
            return null;
        }
    }

    /**
     * 保存验证码到数据库
     */
    private void saveCaptchaToDatabase(String captchaId, String captchaValue, Integer captchaType, String target) {
        Captcha captcha = new Captcha();
        captcha.setCaptchaId(captchaId);
        captcha.setCaptchaType(captchaType);
        captcha.setCaptchaValue(captchaValue);
        captcha.setTarget(target);
        captcha.setUsed(0);
        captcha.setExpireTime(LocalDateTime.now().plusMinutes(
            captchaType == 1 ? CAPTCHA_EXPIRE_MINUTES : SMS_CAPTCHA_EXPIRE_MINUTES
        ));
        
        captchaMapper.insert(captcha);
    }

    /**
     * 检查短信验证码发送频率
     */
    private boolean isSmsCaptchaLimitExceeded(String phone) {
        // 检查1分钟内是否已发送过
        int count = captchaMapper.countByTargetAndType(phone, 2, 1);
        return count > 0;
    }

    /**
     * 检查邮箱验证码发送频率
     */
    private boolean isEmailCaptchaLimitExceeded(String email) {
        // 检查1分钟内是否已发送过
        int count = captchaMapper.countByTargetAndType(email, 3, 1);
        return count > 0;
    }
} 